package com.nodusk.service;

import com.google.common.base.CaseFormat;
import com.nodusk.model.ColumnClass;
import com.nodusk.model.Response;
import com.nodusk.model.TableClass;
import com.nodusk.util.DbUtils;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


@Service
public class GenerateCodeService {
    @Autowired
    private Configuration freemarkerConfiguration;

    public Response generateCode(List<TableClass> tableClassList, String realPath) {
        try {
            Template modelTemplate = freemarkerConfiguration.getTemplate("Model.java.ftl");
            Template mapperJavaTemplate = freemarkerConfiguration.getTemplate("Mapper.java.ftl");
            Template mapperXmlTemplate = freemarkerConfiguration.getTemplate("Mapper.xml.ftl");
            Template serviceTemplate = freemarkerConfiguration.getTemplate("Service.java.ftl");
            Template serviceImplTemplate = freemarkerConfiguration.getTemplate("ServiceImpl.java.ftl");
            Template controllerTemplate = freemarkerConfiguration.getTemplate("Controller.java.ftl");
            Connection connection = DbUtils.getConnection();
            DatabaseMetaData metaData = connection.getMetaData();

            for (TableClass tableClass : tableClassList) {
//                ResultSet tables = metaData.getTables(null, null, tableClass.getTableName(), new String[]{"TABLE","VIEW","SYSTEM TABLE", "GLOBAL TEMPORARY","LOCAL  TEMPORARY","ALIAS","SYSNONYM"});
//                String remarksTable=null;
//               while (tables.next()){
//                   String table_name = tables.getString("TABLE_NAME");
//                   remarksTable= tables.getString("REMARKS");
//                   System.out.println();
//               }

                ResultSet columns = metaData.getColumns(connection.getCatalog(), null, tableClass.getTableName(), null);
                //   ResultSet primaryKeys = metaData.getPrimaryKeys(connection.getCatalog(), null, tableClass.getTableName());
                List<ColumnClass> columnClassList = new ArrayList<>();
                List<ColumnClass> primaryKeyColumns = new ArrayList<>();
                Set<String> primaryKeyss = new HashSet<String>();
                ResultSet pk_rs = metaData.getPrimaryKeys(null, null, tableClass.getTableName());
                while (pk_rs.next()) {
                    primaryKeyss.add(pk_rs.getString("COLUMN_NAME"));
                }
                while (columns.next()) {
                    String column_name = columns.getString("COLUMN_NAME");
                    String type_name = columns.getString("TYPE_NAME");
                    String remarks = columns.getString("REMARKS");
                    String is_nullable = columns.getString("IS_NULLABLE");

                    String is_autoincrement = columns.getString("IS_AUTOINCREMENT");
                    String javaType = "";
                    ColumnClass columnClass = new ColumnClass();
                    columnClass.setRemark(remarks);
                    columnClass.setIsAutoincrement(is_autoincrement);
                    columnClass.setColumnName(column_name);
                    columnClass.setIsNullable(is_nullable);
                    if (type_name.equals("DATETIME")) {
                        type_name = "TIMESTAMP";
                        javaType = "Date";
                    } else if (type_name.equals("TEXT")) {
                        type_name = "LONGVARCHAR";
                        javaType = "String";
                    } else if (type_name.equals("VARCHAR") || type_name.equals("CHAR")) {

                        javaType = "String";
                    } else if (type_name.equals("DATE")) {

                        javaType = "Date";
                    } else if (type_name.equals("SMALLINT")) {

                        javaType = "Short";
                    } else if (type_name.equals("BIGINT")) {

                        javaType = "Long";
                    } else if (type_name.equals("DOUBLE")) {

                        javaType = "Double";
                    } else if (type_name.equals("BIT")) {

                        javaType = "Boolean";
                    } else if (type_name.equals("DECIMAL")) {

                        javaType = "BigDecimal";
                    } else if (type_name.equals("BLOB") || type_name.equals("LONGBLOB")) {
                        type_name = "BLOB";
                        javaType = "byte[]";
                    } else if (type_name.equals("INT") || type_name.contains("INT")) {
                        type_name = "INTEGER";
                        javaType = "Integer";
                    }

                    columnClass.setJavaType(javaType);
                    columnClass.setType(type_name);
                    columnClass.setPropertyName(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, column_name));
                    //   primaryKeys.first();
                    if (primaryKeyss.contains(column_name)) {
                        columnClass.setIsPrimary("true");
                    } else {
                        columnClass.setIsPrimary("false");
                    }
//                    while (primaryKeys.next()) {
//                        String pkName = primaryKeys.getString("COLUMN_NAME");
//                        if (column_name.equals(pkName)) {
//                            columnClass.setPrimary(true);
//                        }
//                    }
                    columnClassList.add(columnClass);
                    if (columnClass.getIsPrimary() != null && columnClass.getIsPrimary().equals("true")) {
                        primaryKeyColumns.add(columnClass);
                    }
                }
                tableClass.setColumns(columnClassList);
                tableClass.setPrimaryKeyColumns(primaryKeyColumns);
                String path = realPath + "/" + tableClass.getPackageName().replace(".", "/");
                generate(modelTemplate, tableClass, path + "/pojo/");
                generate(mapperJavaTemplate, tableClass, path + "/mapper/");
                generate(mapperXmlTemplate, tableClass, path + "/mapper/");
                generate(serviceTemplate, tableClass, path + "/service/");
                generate(serviceImplTemplate, tableClass, path + "/service/impl/");
                generate(controllerTemplate, tableClass, path + "/controller/");
            }
            return Response.ok("代码生成成功", realPath);
        } catch (IOException | SQLException | TemplateException e) {
            e.printStackTrace();
        }
        return Response.error("代码生成失败");
    }

    private void generate(Template template, TableClass tableClass, String path) throws IOException, TemplateException {
        File folder = new File(path);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        String fileName = path + "/" + tableClass.getModelName() + template.getName().replace(".ftl", "").replace("Model", "");
        FileOutputStream fos = new FileOutputStream(fileName);
        OutputStreamWriter out = new OutputStreamWriter(fos);
        template.process(tableClass, out);
        fos.close();
        out.close();
    }

//    public boolean isExistByTableName(String tableName)
//            throws ClassNotFoundException, SQLException {
//        tableName = tableName == null ? null : tableName.toUpperCase();
//        Set<String> tableNames = getTableNames();
//        return tableNames.contains(tableName);
//    }
//    /**
//     * 通过表名获取表主键信息
//     *
//     * @param tableName
//     *            表名
//     * @return 表信息
//     * @throws SQLException
//     * @throws ClassNotFoundException
//     */
//    public Set<String> getPrimaryKeysByName(String tableName)
//            throws SQLException, ClassNotFoundException {
//        if (tableName != null) {
//            tableName = tableName.toUpperCase();
//        } else {
//            return null;
//        }
//        if (!isExistByTableName(tableName)) {
//            return null;
//        } else if (tablesPrimaryKeys.containsKey(tableName)) {
//            return tablesPrimaryKeys.get(tableName);
//        }
//        Set<String> primaryKeys = new HashSet<String>();
//        DatabaseMetaData meta = getConnection().getMetaData();
//        ResultSet pk_rs = meta.getPrimaryKeys(null, null, tableName);
//        while (pk_rs.next()) {
//            primaryKeys.add(pk_rs.getString("COLUMN_NAME"));
//        }
//        tablesPrimaryKeys.put(tableName, primaryKeys);
//        return primaryKeys;
//    }
}
